<?php
include_once('/var/www/html/new/com.inc.php');
include_once('/var/www/html/new/d/class/Terminal_Check_Socket.class.php');


exit;

$ac = $GLOBALS['_ac'];
$pw = $GLOBALS['_pw'];
$s  = new SoapClient(null,array("location" => "http://localhost/open/openService/pft_insideMX.php","uri" => "www.16u.com?ac_16u=$ac|pw_16u=$pw|auth_16u=true"));


$orderid = $_REQUEST['id'];
$resxml = $s->Order_Globle_Search("","","","","","","","","","","","", $orderid,"","","","","",1,1,0,1,"","","","","","","","","",0,1);
$simxml = simplexml_load_string($resxml);
// if(!isset($simxml->Rec)) Response("[$orderid]订单查找失败", 204);

$salerid = (string)$simxml->Rec->UUsalerid;
$voucher = (string)$simxml->Rec->UUcode;

// if((int)$simxml->Rec->UUstatus==3) Response("[$orderid]订单已取消", 105);
// if((int)$simxml->Rec->UUstatus==1 && (string)$simxml->Rec->UUpack_order==0) Response("[$orderid]订单已验证", 1077);


if(strlen($salerid)==8){// 终端合并新终端号
	$sql = "select nowTerminal,nowSalerID from pft_terminal_share where nowSalerID='$salerid' limit 1";
	$GLOBALS['le']->query($sql);
	if(!$GLOBALS['le']->fetch_assoc()) exit('{"status":"fail","msg":"未找到景区"}');
	$salerid       = $GLOBALS['le']->f('nowSalerID');
	$terminal_inum = $GLOBALS['le']->f('nowTerminal');
	$terminal_type = 1;
}else{
	$sql = "select terminal,terminal_type,salerid from uu_land where salerid=$salerid limit 1";
	$GLOBALS['le']->query($sql);
	if(!$GLOBALS['le']->fetch_assoc()) exit('{"status":"fail","msg":"未找到景区"}');
	$terminal_inum = $GLOBALS['le']->f('terminal');
	$terminal_type = $GLOBALS['le']->f('terminal_type');
}


$tc = Terminal_Check_Socket::connect();
$rs = $tc->Terminal_Check_In_Voucher($terminal_inum, $salerid, $voucher,array('vCmd'=>498));
print_r($rs);






class Terminal_Check_Socket1{
	
	
	
	private $socket  = null;
	private $conn    = null;
	private $chkCode = array( 3 => '软终端', 5 => '自助机', 7 => '外部消费通知');
	private $errCode = array( '101' => '服务器连接失败', '290' => '订单未找到', '519' => '游玩时间未到', '288' => '订单已过期', '293' => '订单已验证',
		'521' => '验证时间未到'
	);
	

	public static $instance = array();

	// 单例对象
	public static function connect($ipv4='121.40.69.184', $port='2347'){
		$server = md5($ipv4.$port);
		if(isset($instance[$server])) return $instance[$server];
		self::$instance[$server] = new self($ipv4, $port);
		return self::$instance[$server];
	}
	
	// 私有构造连接
	public function __construct($ipv4='121.40.69.184', $port='2347'){
		$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
		if($this->socket<0) exit('Create Socket Error.');
		if(!socket_connect($this->socket, $ipv4, $port)) exit('Connect Socket Error.');
	}
	
	
	public static function reverse($string, $length = 2){
		$newStr = implode(array_reverse(str_split($string, $length)));
		return $newStr;
	}
	
	
	
	// 配置参数检查
	public function Terminal_Params_Verify(Array $cfg){
		
		$iConf = array('vMode' => 3, 'vCmd' => 260);
		$iConf = array_merge($iConf, $cfg);
		
		// 499 绕过验证限制
		if(!in_array($iConf['vCmd'], array(260,499, 498, 289, 288))) return array('state'=>'fail','msg'=>'指令不存在');
		if(!in_array($iConf['vMode'], array(3,5,7,8)))  return array('state'=>'fail','msg'=>'验证方式不正确');
		
		return array('state'=>'success', 'cfg'=>$iConf);
	}
	
	// 新旧终端验证方式监测
	public function Terminal_Check_Type_Detect($terminal_num){
		
		return true;
		// $sql = "select terminal,terminal_type,salerid from uu_land where terminal=$terminal_num limit 1";
		// $GLOBALS['le']->query($sql);
		// $GLOBALS['le']->fetch_assoc();
		// if($GLOBALS['le']->f('terminal_type')==1) return true;
	
		// 登陆（签到）切换新终端
		// $hexData = unpack('H*', '01,v01.30');
		// $pkgData = $pkgData.$hexData[1];
		// $pkgData = self::Terminal_Data_Package($terminal_num, $pkgData, array('vCmd'=>257, 'vMode'=>8));
		// $clsData = $this->Send_And_Receive(pack('H*' , $pkgData));
		
		// $stateData = substr($clsData, 28, 4);
		// return ($stateData=='0000') ? true:false;
	}
	
	
	// 数据头部公告
	public static function Terminal_Data_Package($terminal_num, $sData, Array $cfg = array()){
		
		if(!isset($cfg['vMode'])) $cfg['vMode'] = 3;
		$pData  = '4d21';
		$sData .= '00';
		$pLens  = strlen($sData);
		$terHex = str_pad(dechex($pLens), 4, '0', STR_PAD_LEFT);
		$pData .= self::reverse($terHex);// 数据长度
		$pData .= str_pad($hex, 8, $cfg['vMode'], STR_PAD_LEFT); // 填充验证方式 $cfg['vMode']
		// $pData .= str_pad($hex, 8, 8, STR_PAD_LEFT); // 填充验证方式 $cfg['vMode']
		$terHex = str_pad(dechex($terminal_num), 8, '0', STR_PAD_LEFT);
		$pData .= self::reverse($terHex);// 终端号转换
		$terHex = str_pad(dechex($cfg['vCmd']), 4, '0', STR_PAD_LEFT);
		$pData .= self::reverse($terHex);// 指令转换
		$pData  = $pData.'0000'.$sData;
		return $pData;
	}
	
	// 查询订单
	public function Terminal_Query_Order_Voucher($terminal_num, $salerid, $voucher, Array $cfg = array()){
		
		// 参数校验
		if(!$terminal_num || !$salerid || !$voucher) return array('state'=>'fail', 'msg'=>'参数错误');
		
		$cfg['vCmd']  = 288;
		$clsResult = $this->Terminal_Params_Verify($cfg);
		if($clsResult['state']=='fail') return $clsResult;
		
		if(!isset($cfg['vTerminal_Detect']) || $cfg['vTerminal_Detect']!=0)
			if(!$this->Terminal_Check_Type_Detect($terminal_num)) return array('state'=>'fail', 'msg'=>'新旧终端验证切换失败:'.$terminal_num);
			
		// 组装数据
		$hexData = unpack('H*', $salerid.$voucher);
		$pkgData = $pkgData.$hexData[1];
		
		$pkgData = self::Terminal_Data_Package($terminal_num, $pkgData, $clsResult['cfg']);
		$clsData = $this->Send_And_Receive($pkgData);

		$resData = substr($clsData, 28, 4);
		if($resData!='0000') return $this->ErrorFormat($resData);
		
		$relData = substr($clsData, 32, -2);
		$relData = mb_convert_encoding(pack('H*', $relData), 'UTF-8', 'GBK');
		return $relData;
	}
	
	// 凭证码验证
	public function Terminal_Check_In_Voucher($terminal_num, $salerid, $voucher, Array $cfg = array()){	
		
		// 参数校验
		if(!$terminal_num || !$salerid || !$voucher) return array('state'=>'fail', 'msg'=>'参数错误');
		
		$clsResult = $this->Terminal_Params_Verify($cfg);
		if($clsResult['state']=='fail') return $clsResult;
		
		// 新旧终端验证切换监测
		if(!isset($cfg['vTerminal_Detect']) || $cfg['vTerminal_Detect']!=0)
			if(!$this->Terminal_Check_Type_Detect($terminal_num)) return array('state'=>'fail', 'msg'=>'新旧终端验证切换失败');
		
		// 组装数据
		$hexData = unpack('H*', $salerid.$voucher);
		echo $hexData[1];
		if(($cfg['vCmd']==498 || $cfg['vCmd']==499) && isset($cfg['vCheckDate'])){// 传入验证时间
			$chkDate = date('YmdHis', strtotime($cfg['vCheckDate']));
			$hexData = unpack('H*', $salerid.$voucher.','.$chkDate);
		}
		
		
		$pkgData = $pkgData.$hexData[1];
		$pkgData = self::Terminal_Data_Package($terminal_num, $pkgData, $clsResult['cfg']);
		// echo $pkgData;
		$clsData = $this->Send_And_Receive($pkgData);
		return $this->format($clsData);
	}
	
	
	// 手机号验证
	public function Terminal_Check_In_Mobile($terminal_num, $salerid, $mobile, Array $cfg = array()){
		
		// 参数校验
		if(!$terminal_num || !$salerid || !$mobile) return array('state'=>'fail', 'msg'=>'参数错误');
		
		$clsResult = $this->Terminal_Params_Verify($cfg);
		if($clsResult['state']=='fail') return $clsResult;
		
		// 新旧终端验证切换监测
		if(!isset($cfg['vTerminal_Detect']) || $cfg['vTerminal_Detect']!=0)
			if(!$this->Terminal_Check_Type_Detect($terminal_num)) return array('state'=>'fail', 'msg'=>'新旧终端验证切换失败');
		
		// 组装数据
		$hexData = unpack('H*', $salerid.'U'.$mobile);
		$pkgData = $pkgData.$hexData[1];
		$pkgData = self::Terminal_Data_Package($terminal_num, $pkgData, $clsResult['cfg']);		
		$clsData = $this->Send_And_Receive($pkgData);
		return $this->format($clsData);
	}
	

	
	// 凭证码改单验证
	public function Terminal_ChangeCheck_In_Voucher($terminal_num, $salerid, $voucher, $totalTicket, $tiecketData, Array $cfg=array()){
		
		// 参数校验
		if(!$terminal_num || !$salerid || !$voucher) return array('state'=>'fail', 'msg'=>'参数错误');
		
		$cfg['vCmd'] = 289;
		$clsResult   = $this->Terminal_Params_Verify($cfg);
		if($clsResult['state']=='fail') return $clsResult;
		
		// 新旧终端验证切换监测
		if(!isset($cfg['vTerminal_Detect']) || $cfg['vTerminal_Detect']!=0)
			if(!$this->Terminal_Check_Type_Detect($terminal_num)) return array('state'=>'fail', 'msg'=>'新旧终端验证切换失败');
		
		// 组装数据
		$checkData = '';
		$tickets = array_chunk($tiecketData, 2);
		foreach($tickets as $row) $checkData.= implode(',', $row).'|';
		$checkData = rtrim($checkData, '|');

		$hexData = unpack('H*',$totalTicket.'|'.$salerid.$voucher.'|'.$checkData);
		$pkgData = $pkgData.$hexData[1];
		$pkgData = self::Terminal_Data_Package($terminal_num, $pkgData, $clsResult['cfg']);
		$clsData = $this->Send_And_Receive($pkgData);
		return $this->format($clsData);
	}
	
	
	// 数据解析
	public function format($hexStr_f){
		
		$stateData = substr($hexStr_f, 28, 4);
		if($stateData!='0000') return $this->ErrorFormat($stateData, $hexStr_f);
		
		
		$hexStr   = substr($hexStr_f, 32, -2);
		$parseStr = mb_convert_encoding(pack('H*', $hexStr), 'UTF-8', 'GBK');
		$parseArr = explode(',', $parseStr);
		
		// -1 多单标识
		if($parseArr[0]==-1) return $this->Mulit_Format($hexStr_f);
		
		$response = array();
		
		$response['state'] = 'success';
		$response[] = $parseArr[0];  // 网点编号
		$response[] = $parseArr[1];  // 网点名称
		$response[] = $parseArr[2];  // 取票人姓名
		$response[] = $parseArr[3];  // 取票人手机
		$response['ordernum'] = $parseArr[4];  // 订单号
		$response['orderstatus'] = $parseArr[5];  // 订单状态
		$response['ordertotalPrice'] = $parseArr[6];  // 总金额
		$response[] = $parseArr[7];  // 预付金额
		$response[] = $parseArr[8];  // 支付方式
		$response[] = $parseArr[9];  // 商户ID+凭证号
		$response[] = $parseArr[10]; // 预订时间
		$response[] = $parseArr[11]; // 更新时间
		$response[] = $parseArr[12]; // 起始时间
		$response[] = $parseArr[13]; // 终止时间
		$response[] = $parseArr[14]; // 流水号
		$response[] = $parseArr[15]; // 商品种类个数

		if(strpos($parseArr[0],'-2')===0){// 演出类
			$tickets1 = array_slice($parseArr, 17);
			$tickets2 = array_chunk($tickets1, 5);
			$keys = array('ticket_pid', 'ticket_name', 'ticket_price', 'ticket_num', 'ticket_seat');
			foreach($tickets2 as $row) $response['tickets'][] = array_combine($keys, $row);
		}else{
			$tickets1 = array_slice($parseArr, 16);
			$tickets2 = array_chunk($tickets1, 4);
			$keys = array('ticket_pid', 'ticket_name', 'ticket_price', 'ticket_num');
			foreach($tickets2 as $row) $response['tickets'][] = array_combine($keys, $row);
		}
		return $response;
	}
	
	
	// 错误格式
	public function ErrorFormat($stateCode, $srcPckData=''){
	
		$stateCode_a = str_split($stateCode, 2);
		$stateCode_a = array_reverse($stateCode_a);
		$stateCode_b = implode('', $stateCode_a);
		$stateCode_b = hexdec($stateCode_b);
		return array('state'=>'fail', 'code'=>$stateCode_b, 'msg'=>$this->errCode[$stateCode_b],'pckData'=>$srcPckData);
	}
	
	// 返回多单数据
	public function Mulit_Format($hexStr){

		$hexStr   = substr($hexStr, 32);
		$hexStr   = substr($hexStr, 0, -2);
		$parseStr = mb_convert_encoding(pack('H*', $hexStr), 'UTF-8', 'GBK');
		$parseArr = explode(',', $parseStr);
		$tickets1 = array_slice($parseArr, 1);
		$tickets2 = array_chunk($tickets1, 4);
		$response = array('state'=>'success','multi'=>1);
		$keys = array('ticket_name', 'ticket_enddate', 'ticket_num', 'ticket_code');
		foreach($tickets2 as $row) $response['tickets'][] = array_combine($keys, $row);
		return $response;
	}
	
			
	// 发送数据并返回数据
	public function Send_And_Receive($senddata){
		// if($_SESSION['sid']==1433) exit($senddata);
		Terminal_Check_Socket::logs($senddata);
		
		$senddata = pack('H*' , $senddata);
		// 发送
		if(!socket_write($this->socket, $senddata, strlen($senddata)))
			throw new Exception("socket_write() failed: reason: " . socket_strerror($this->socket) . "\n");
		
		// 接收
		$hexStr = '';
		while($out = socket_read($this->socket, 8192)){
			$hexStr = bin2hex($out);
			break;
		}
		return $hexStr;
	}
	
	public function __destruct(){
		socket_close($this->socket);
	}
	
	public static function logs($content, $file=''){
		if($file=='') $file = '/var/www/html/new/d/logs/terminal_check/terminal_check_data'.date('Ymd').'.log';
		$fp = fopen($file,"a");
		flock($fp, LOCK_EX);
		fwrite($fp,date("Y-m-d H:i:s").":".$content."\n");
		flock($fp, LOCK_UN);
		fclose($fp);
	}
}
